//
// Vector.cpp for  in /home/herpec_j/Dropbox/Projets/raytracer-2016/Sources/Maths/
//
// Made by Jonathan
// Login   <ledey_l@epitech.net>
//
// Started on  Sun Sep 22 11:29:33 2013 Jonathan
// Last update Tue Sep 24 20:09:37 2013 Jonathan
//

#include		"Maths/Vector.hpp"
#include		"Maths/Normal.hpp"
#include		"Maths/Point.hpp"
#include		"Maths/Matrix.hpp"

namespace		Maths
{
  Vector::Vector(void) : mX(0.0f), mY(0.0f), mZ(0.0f)
  {
    return;
  }

  Vector::Vector(long double rValue) : mX(rValue), mY(rValue), mZ(rValue)
  {
    return;
  }

  Vector::Vector(long double rX, long double rY, long double rZ) : mX(rX), mY(rY), mZ(rZ)
  {
    return;
  }

  Vector::Vector(Vector const &rOther) : mX(rOther.mX), mY(rOther.mY), mZ(rOther.mZ)
  {
    return;
  }

  Vector::Vector(Normal const &rNormal) : mX(rNormal[0]), mY(rNormal[1]), mZ(rNormal[2])
  {
    return;
  }

  Vector::Vector(Point const &rPoint) : mX(rPoint[0]), mY(rPoint[1]), mZ(rPoint[2])
  {
    return;
  }

  Vector		&Vector::operator=(Vector const &rOther)
  {
    if (this != &rOther)
      {
	mX = rOther.mX;
	mY = rOther.mY;
	mZ = rOther.mZ;
      }
    return (*this);
  }

  Vector		&Vector::operator=(Normal const &rNormal)
  {
    mX = rNormal[0];
    mY = rNormal[1];
    mZ = rNormal[2];
    return (*this);
  }

  Vector		&Vector::operator=(Point const &rPoint)
  {
    mX = rPoint[0];
    mY = rPoint[1];
    mZ = rPoint[2];
    return (*this);
  }

  Vector		Vector::operator-(void) const
  {
    return (Vector(-mX, -mY, -mZ));
  }

  Vector		Vector::operator+(Vector const &rOther) const
  {
    return (Vector(mX + rOther.mX, mY + rOther.mY, mZ + rOther.mZ));
  }

  Vector		&Vector::operator+=(Vector const &rOther)
  {
    mX += rOther.mX;
    mY += rOther.mY;
    mZ += rOther.mZ;
    return (*this);
  }

  Vector		Vector::operator-(Vector const &rOther) const
  {
    return (Vector(mX - rOther.mX, mY - rOther.mY, mZ - rOther.mZ));
  }

  Vector		&Vector::operator-=(Vector const &rOther)
  {
    mX -= rOther.mX;
    mY -= rOther.mY;
    mZ -= rOther.mZ;
    return (*this);

  }

  Vector		Vector::operator*(long double rValue) const
  {
    return (Vector(mX * rValue, mY * rValue, mZ * rValue));
  }

  long double		Vector::operator*(Vector const &rOther) const
  {
    return (mX * rOther.mX + mY * rOther.mY + mZ * rOther.mZ);
  }

  Vector		Vector::operator/(long double rValue) const
  {
    return (Vector(mX / rValue, mY / rValue, mZ / rValue));
  }

  Vector		Vector::operator^(Vector const &rOther) const
  {
    return (Vector(mY * rOther.mZ - mZ * rOther.mY,
		   mZ * rOther.mX - mX * rOther.mZ,
		   mX * rOther.mY - mY * rOther.mX));
  }

  long double		Vector::operator[](int rIndex) const
  {
    switch (rIndex)
      {
      case 0:
	return (mX);
	break;
      case 1:
	return (mY);
	break;
      case 2:
	return (mZ);
	break;
      default:
	return (0.0f);
	break;
      }
  }

  long double  		Vector::Length(void) const
  {
    return (sqrt(mX * mX + mY * mY + mZ * mZ));
  }

  long double		Vector::Length_Squared(void) const
  {
    return (mX * mX + mY * mY + mZ * mZ);
  }

  void			Vector::Normalize(void)
  {
    long double		length = sqrt(mX * mX + mY * mY + mZ * mZ);

    mX /= length;
    mY /= length;
    mZ /= length;
  }

  Vector		&Vector::Hat(void)
  {
    long double		length = sqrt(mX * mX + mY * mY + mZ * mZ);

    mX /= length;
    mY /= length;
    mZ /= length;
    return (*this);
  }

  Vector::~Vector(void)
  {
    return;
  }

  Vector		operator*(long double rValue, Vector const &rVector)
  {
    return (Vector(rValue * rVector[0], rValue * rVector[1], rValue * rVector[2]));
  }

  Vector		operator*(Matrix const &rMatrix, Vector const &rVector)
  {
    long double		**matrix = rMatrix.GetMatrix();
    long double		x = rVector[0];
    long double		y = rVector[1];
    long double		z = rVector[2];

    return (Vector(matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z,
		   matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z,
		   matrix[2][0] * x + matrix[2][1] * y + matrix[2][2] * z));
  }
};
